#include <stdio.h>
#include <stdlib.h>

#define BROKEN_PIPE_ERROR -2

#ifdef _WIN32
#include<winsock2.h>
#include<windows.h>

#define SHUT_RD SD_RECEIVE
#define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH
#endif


#ifndef LOGE
#define LOGE(fmt, ...) printf(fmt, __VA_ARGS__)
#else
//#define LOG_TAG "netforward"
//#include "debug.h"
#endif


/*
below may be usefull
*/


/* Forward data between sockets */
void forward_data(int source_sock, int destination_sock) {
    ssize_t n;

#ifdef USE_SPLICE
    int buf_pipe[2];

    if (pipe(buf_pipe) == -1) {
        LOGE("%s\n", "pipe: %m");
        exit(CREATE_PIPE_ERROR);
    }

    while ((n = splice(source_sock, NULL, buf_pipe[WRITE], NULL, SSIZE_MAX, SPLICE_F_NONBLOCK|SPLICE_F_MOVE)) > 0) {
        if (splice(buf_pipe[READ], NULL, destination_sock, NULL, SSIZE_MAX, SPLICE_F_MOVE) < 0) {
            LOGE("%s\n", "write: %m");
            exit(BROKEN_PIPE_ERROR);
        }
    }
#else
    char buffer[BUFSIZ];

    while ((n = recv(source_sock, buffer, BUFSIZ, 0)) > 0) { // read data from input socket
        send(destination_sock, buffer, n, 0); // send data to output socket
    }
#endif

    if (n < 0) {
        LOGE("%s\n", "read: %m");
        exit(BROKEN_PIPE_ERROR);
    }

#ifdef USE_SPLICE
    close(buf_pipe[0]);
    close(buf_pipe[1]);
#endif

    shutdown(destination_sock, SHUT_RDWR); // stop other processes from using socket
    closesocket(destination_sock);

    shutdown(source_sock, SHUT_RDWR); // stop other processes from using socket
    closesocket(source_sock);
}

/*/////////////////////////////////////////////////////=======================================================

IOCP TCP


//////// */

#define PORT	1987		//监听端口
#define BUFSIZE 1024		//数据缓冲区大小

typedef struct 
{
	SOCKET s;				//套接字句柄
	struct sockaddr_in addr;		//对方的地址
} PER_HANDLE_DATA, *PPER_HANDLE_DATA;

typedef struct 
{
	OVERLAPPED ol;			//重叠结构
	char buf[BUFSIZE];		//数据缓冲区
	int nOperationType;		//操作类型
} PER_IO_DATA, *PPER_IO_DATA;

//自定义关注事件
#define OP_READ		100
#define OP_WRITE	200


DWORD WINAPI WorkerThread(LPVOID ComPortID)
{
	HANDLE cp = (HANDLE)ComPortID;

	DWORD	btf;
	PPER_IO_DATA pid;
    PPER_HANDLE_DATA phd;
    DWORD   SBytes, RBytes;
    DWORD   Flags;

	while(1)
	{
		//关联到完成端口的所有套接口等待IO准备好
		if(GetQueuedCompletionStatus(cp, &btf, (LPDWORD)&phd, 
			(LPOVERLAPPED *)&pid, WSA_INFINITE) == 0){
				return 0;
		}
	
		//当客户端关闭时会触发
		if(0 == btf && (pid->nOperationType == OP_READ || pid->nOperationType == OP_WRITE)) {
			closesocket(phd->s);

			GlobalFree(pid);
			GlobalFree(phd);

			printf("client closed\n");
			continue;
		}

		WSABUF buf;
		//判断IO端口的当前触发事件(读入or写出)
		switch(pid->nOperationType){
		case OP_READ:

			pid->buf[btf] = '\0';
			printf("Recv: %s\n", pid->buf);

			char sendbuf[BUFSIZE];
			sprintf(sendbuf,"Server Got \"%s\" from you",pid->buf);

			//继续投递写出的操作
			buf.buf = sendbuf;
			buf.len = strlen(sendbuf)+1;
			pid->nOperationType = OP_WRITE;

			SBytes = 0;

			//让操作系统异步输出吧
			WSASend(phd->s, &buf, 1, &SBytes, 0, &pid->ol, NULL);
			break;
		case OP_WRITE:

			pid->buf[btf] = '\0';
			printf("Send: Server Got \"%s\"\n\n", pid->buf);

			//继续投递读入的操作
			buf.buf = pid->buf;
			buf.len = BUFSIZE;
			pid->nOperationType = OP_READ;

			RBytes = 0;
			Flags = 0;

			//让底层线程池异步读入吧
			WSARecv(phd->s, &buf, 1, &RBytes, &Flags, &pid->ol, NULL);
			break;
		}
	}

	return 0;
}

void init()
{

    WSADATA wsaData;

	/*
	* 加载指定版本的socket库文件
	*/
	WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
	printf("server start running\n");


    HANDLE completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    
    //创建一个工作线程，传递完成端口
	CreateThread(NULL, 0, WorkerThread, completionPort, 0, 0);

	/*
	* 初始化网络套接口
	*/
	SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(PORT);
		
	bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

	listen(sockSrv,5);

	/*
	* 等待通信
	*/
	while (1)
	{
		SOCKADDR_IN  addrClient;
		int len=sizeof(SOCKADDR);

		SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);

		//为新连接创建一个handle，关联到完成端口对象
		PPER_HANDLE_DATA phd = (PPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
		phd->s = sockConn;
		memcpy(&phd->addr, &addrClient, len);

		CreateIoCompletionPort((HANDLE)phd->s, completionPort,(DWORD)phd, 0);

		//分配读写
		PPER_IO_DATA pid = (PPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));

		ZeroMemory(&(pid->ol), sizeof(OVERLAPPED));

		//初次投递读入的操作，让操作系统的线程池去关注IO端口的数据接收吧
		pid->nOperationType = OP_READ;
		WSABUF buf;
		buf.buf = pid->buf;
		buf.len = BUFSIZE;
		DWORD dRecv = 0;
		DWORD dFlag = 0;
		
		//一般服务器都是被动接受客户端连接，所以只需要异步Recv即可
		WSARecv(phd->s, &buf, 1, &dRecv, &dFlag, &pid->ol, NULL);
	}


}